package com.ctrip.openapi.java.base;

import cn.buk.util.DateUtil;
import com.ctrip.openapi.java.utils.ConfigData;
import com.ctrip.openapi.java.utils.GzipUtil;
import com.ctrip.openapi.java.utils.SignatureUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;

import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

// Http访问器
public class HttpAccessAdapter {

	private static Logger logger = Logger.getLogger(HttpAccessAdapter.class);

	// Http请求静态信息
	private static ArrayList<HttpRequestProperty> StaticHttpRequestProperty = LoadStaticHttpRequestProperties();
	private static ArrayList<HttpRequestProperty> StaticHttpRequestProperty2 = LoadStaticHttpRequestProperties2();
	private static ArrayList<HttpRequestProperty> StaticHttpRequestProperty3 = LoadStaticHttpRequestProperties3();
	private static ArrayList<HttpRequestProperty> StaticHttpRequestProperty4 = LoadStaticHttpRequestProperties4();

	// 发送指定的请求到指定的URL上
	public static String SendRequestToUrl(String requestContent, String urlString, String paraName, Proxy proxy) {
		InputStream errorStream = null;
		HttpURLConnection httpCon = null;
		try {
			URL url = new URL(urlString);
			String content = XMLToString(requestContent);
			String soapMessage = AddSoapShell(content);
			if (proxy == null)
				httpCon = (HttpURLConnection) url.openConnection();
			else
				httpCon = (HttpURLConnection) url.openConnection(proxy);
			httpCon.setRequestMethod("POST");
			httpCon.setDoOutput(true);
			httpCon.setDoInput(true);

			for (int i = 0; i < StaticHttpRequestProperty.size(); i++) {
				httpCon.setRequestProperty(StaticHttpRequestProperty.get(i).getName(),
						StaticHttpRequestProperty.get(i).getValue());
			}

			httpCon.setRequestProperty("Content-Length", String.valueOf(soapMessage.length()));

			OutputStream outputStream = httpCon.getOutputStream();
			outputStream.write(soapMessage.getBytes("UTF-8"));
			outputStream.close();

			InputStream inputStream = httpCon.getInputStream();
			// String encoding = httpCon.getRequestProperty("Accept-Encoding");
			BufferedReader br = null;
			// httpCon.getResponseMessage();
			if (httpCon.getRequestProperty("Accept-Encoding") != null) {
				try {
					GZIPInputStream gzipStream = new GZIPInputStream(inputStream);
					br = new BufferedReader(new InputStreamReader(gzipStream, "UTF-8"));
				} catch (IOException e) {
					br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
				}
			} else {
				br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
			}
			StringBuffer result = new StringBuffer();
			String line = null;
			while ((line = br.readLine()) != null) {
				result.append(line);
			}
			return StringToXML(RemoveSoapShell(result.toString()));

		} catch (MalformedURLException ex) {
			logger.error(ex.getMessage());
		} catch (IOException ex) {
			errorStream = httpCon.getErrorStream();
			if (errorStream != null) {
				String errorMessage = null;
				String line = null;
				BufferedReader br = new BufferedReader(new InputStreamReader(
						errorStream));
				try {
					while ((line = br.readLine()) != null) {
						errorMessage += line;
					}
					return errorMessage;
				} catch (IOException ex1) {
					logger.error(ex1.getMessage());
				}
			}
			logger.error(ex.getMessage());
			try {
				errorStream.close();
			} catch (IOException ex1) {
				logger.error(ex1.getMessage());
			}
		} catch (SdkSystemException ex) {
			logger.error(ex.getMessage());
		} catch (Exception ex) {
			logger.error(ex.getMessage());
		} finally {
			if (httpCon != null) {
				httpCon.disconnect();
			}
		}

		return "";
	}

	public static String SendRequestToUrl2(String requestContent, String urlString, String paraName, Proxy proxy) {
		InputStream errorStream = null;
		HttpURLConnection httpCon = null;
		try {
			URL url = new URL(urlString);
			String content = XMLToString(requestContent);
			String soapMessage = AddSoapShell2(content);
//			System.out.println("soapMessage: " + soapMessage);
//			System.out.println("");

			if (proxy == null)
				httpCon = (HttpURLConnection) url.openConnection();
			else
				httpCon = (HttpURLConnection) url.openConnection(proxy);
			httpCon.setRequestMethod("POST");
			httpCon.setDoOutput(true);
			httpCon.setDoInput(true);

			for (int i = 0; i < StaticHttpRequestProperty2.size(); i++) {
				httpCon.setRequestProperty(StaticHttpRequestProperty2.get(i).getName(),
						StaticHttpRequestProperty2.get(i).getValue());
			}

			httpCon.setRequestProperty("Content-Length", String.valueOf(soapMessage.length()));

			OutputStream outputStream = httpCon.getOutputStream();
			outputStream.write(soapMessage.getBytes("UTF-8"));
			outputStream.close();

			InputStream inputStream = httpCon.getInputStream();
//			 String encoding = httpCon.getRequestProperty("Accept-Encoding");
//			System.out.print("encoding: " + encoding);

//			System.out.print("..........");

			BufferedReader br = null;
			// httpCon.getResponseMessage();
			if (httpCon.getRequestProperty("Accept-Encoding") != null) {
				try {
					GZIPInputStream gzipStream = new GZIPInputStream(inputStream);
					br = new BufferedReader(new InputStreamReader(gzipStream, "UTF-8"));
				} catch (IOException e) {
					br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
				}
			} else {
				br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
			}
			StringBuffer result = new StringBuffer();
			String line = null;
			while ((line = br.readLine()) != null) {
				result.append(line);
			}

//			System.out.println(result.toString());
//			System.out.println("");

			return StringToXML(RemoveSoapShell2(result.toString()));

		} catch (MalformedURLException ex) {
			logger.error(ex.getMessage());
		} catch (IOException ex) {
			logger.error(ex.getMessage());
			errorStream = httpCon.getErrorStream();
			if (errorStream != null) {
				String errorMessage = null;
				String line = null;
				BufferedReader br = new BufferedReader(new InputStreamReader(
						errorStream));
				try {
					while ((line = br.readLine()) != null) {
						errorMessage += line;
					}
					return errorMessage;
				} catch (IOException ex1) {
					logger.error(ex1.getMessage());
				}
			}
			logger.error(ex.getMessage());
			try {
				errorStream.close();
			} catch (IOException ex1) {
				logger.error(ex1.getMessage());
			}
		} catch (SdkSystemException ex) {
			logger.error(ex.getMessage());
		} catch (Exception ex) {
			logger.error(ex.getMessage());
		} finally {
			if (httpCon != null) {
				httpCon.disconnect();
			}
		}

		return "";
	}


	private static byte[] gzipCompress(String val) {
		byte[] result = new byte[0];

		//用gzip方式压缩请求体并赋给request
		ByteArrayInputStream bis = null;
		try {
			bis = new ByteArrayInputStream(val.getBytes("UTF-8"));
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			GZIPOutputStream gos = null;

			gos = new GZIPOutputStream(bos);
			for (int c = bis.read(); c != -1; c = bis.read()) {
				gos.write(c);
			}

			gos.close();

			result = bos.toByteArray();
			bos.close();

		} catch (UnsupportedEncodingException ex) {
			logger.error(ex.getMessage());
		} catch (IOException ex) {
			logger.error(ex.getMessage());
		}

		return result;

	}

	// 压缩
	public static String compress(String str) throws IOException {
		if (str == null || str.length() == 0) {
			return str;
		}
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		GZIPOutputStream gzip = new GZIPOutputStream(out);
		gzip.write(str.getBytes());
		gzip.close();
		return out.toString("ISO-8859-1");
	}

	// 解压缩
	public static String gzipDecompress(String str) throws IOException {
		if (str == null || str.length() == 0) {
			return str;
		}
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		ByteArrayInputStream in = new ByteArrayInputStream(str
				.getBytes("ISO-8859-1"));
		GZIPInputStream gunzip = new GZIPInputStream(in);
		byte[] buffer = new byte[256];
		int n;
		while ((n = gunzip.read(buffer))>= 0) {
			out.write(buffer, 0, n);
		}
		// toString()使用平台默认编码，也可以显式的指定如toString(&quot;GBK&quot;)
		return out.toString("UTF-8");
	}

	/**
	 * 向携程共享平台(国际)低价看板发送请求
	 * @param requestContent
	 * @param urlString
	 * @param
	 * @param
     * @return
     */
	public static String SendRequestToShareIntl(String userId, String password, final int apiType, String requestContent, String urlString) {
		InputStream errorStream = null;
		HttpURLConnection httpCon = null;
		try {
			URL url = new URL(urlString);

			String base64Binary = new String(new Base64().encode(GzipUtil.gZip(requestContent.getBytes())));

			String soapMessage = AddSoapShellToShareIntl(userId, password, apiType, base64Binary);

			httpCon = (HttpURLConnection) url.openConnection();

			httpCon.setRequestMethod("POST");
			httpCon.setDoOutput(true);
			httpCon.setDoInput(true);

			for (int i = 0; i < StaticHttpRequestProperty4.size(); i++) {
				httpCon.setRequestProperty(StaticHttpRequestProperty4.get(i).getName(),
						StaticHttpRequestProperty4.get(i).getValue());
			}

			httpCon.setRequestProperty("Content-Length", String.valueOf(soapMessage.length()));

			OutputStream outputStream = httpCon.getOutputStream();
			outputStream.write(soapMessage.getBytes());
			outputStream.close();

			InputStream inputStream = httpCon.getInputStream();

			BufferedReader br = null;

			if (httpCon.getRequestProperty("Accept-Encoding") != null) {
				try {
					GZIPInputStream gzipStream = new GZIPInputStream(inputStream);
					br = new BufferedReader(new InputStreamReader(gzipStream, "UTF-8"));
				} catch (IOException e) {
					br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
				}
			} else {
				br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
			}
			StringBuffer result = new StringBuffer();
			String line = null;
			while ((line = br.readLine()) != null) {
				result.append(line);
			}

			return RemoveSoapShellFromShareIntl(result.toString());

		} catch (MalformedURLException ex) {
			logger.error(ex.getMessage());
		} catch (IOException ex) {
			logger.error(ex.getMessage());
			errorStream = httpCon.getErrorStream();
			if (errorStream != null) {
				String errorMessage = null;
				String line = null;
				BufferedReader br = new BufferedReader(new InputStreamReader(
						errorStream));
				try {
					while ((line = br.readLine()) != null) {
						errorMessage += line;
					}
					return errorMessage;
				} catch (IOException ex1) {
					logger.error(ex1.getMessage());
				}
			}
			logger.error(ex.getMessage());
			try {
				errorStream.close();
			} catch (IOException ex1) {
				logger.error(ex1.getMessage());
			}
		} catch (Exception ex) {
			logger.error(ex.getMessage());
		} finally {
			if (httpCon != null) {
				httpCon.disconnect();
			}
		}

		return "";
	}

	// 将Soap外壳添加到请求体上
	private static String AddSoapShellToShareIntl(String userId, String password, final int apiType, String base64Binary)  {
		BufferedReader bufferedReader = null;
		try {
			InputStream in;
			if (apiType <= 0)
				in = HttpAccessAdapter.class .getResourceAsStream("/RequestSOAPTemplate_IntlLowPrice.xml");
			else
				in = HttpAccessAdapter.class .getResourceAsStream("/RequestSOAPTemplate_IntlOpenApi.xml");

			bufferedReader = new BufferedReader(new InputStreamReader(in));
			String text = bufferedReader.readLine();
			StringBuilder soapShellStringBuilder = new StringBuilder();
			while (text != null) {
				soapShellStringBuilder.append(text.trim());
				text = bufferedReader.readLine();
			}
			String result = soapShellStringBuilder.toString();
			result = result.replaceAll("userId0", userId);
			result = result.replaceAll("password0", password);

			if (apiType > 0) result = result.replaceAll("apiType0", Integer.toString(apiType));

			result = result.replace("base64Binary0", base64Binary);

			return result;
		} catch (Exception ex) {
			logger.error(ex.getMessage());
		} finally {
			if (bufferedReader != null) {
				try {
					bufferedReader.close();
				} catch (IOException e) {
				}
			}
		}

		return "";
	}
	// 将Soap外壳添加到请求体上
	private static String AddSoapShell2(
			/* String parameterName, */String patameterValue) throws Exception {
		BufferedReader bufferedReader = null;
		try {
			InputStream in = HttpAccessAdapter.class
					.getResourceAsStream("/RequestSOAPTemplate_TBooking.xml");
			bufferedReader = new BufferedReader(new InputStreamReader(in));
			String text = bufferedReader.readLine();
			StringBuilder soapShellStringBuilder = new StringBuilder();
			while (text != null) {
				soapShellStringBuilder.append(text);
				text = bufferedReader.readLine();
			}
			String result = soapShellStringBuilder.toString();
			return result.replaceAll("string", patameterValue);
		} catch (FileNotFoundException e) {
			throw new SdkSystemException("无法找到请求模板文件");
		} catch (IOException e) {
			throw new SdkSystemException("无法读取请求模板文件");
		} finally {
			if (bufferedReader != null) {
				try {
					bufferedReader.close();
				} catch (IOException e) {
				}
			}
		}
	}

	private static String AddSoapShell(
			/* String parameterName, */String patameterValue) throws Exception {
		BufferedReader bufferedReader = null;
		try {
			InputStream in = HttpAccessAdapter.class
					.getResourceAsStream("/RequestSOAPTemplate.xml");
			bufferedReader = new BufferedReader(new InputStreamReader(in));
			String text = bufferedReader.readLine();
			StringBuilder soapShellStringBuilder = new StringBuilder();
			while (text != null) {
				soapShellStringBuilder.append(text);
				text = bufferedReader.readLine();
			}
			String result = soapShellStringBuilder.toString();
			return result.replaceAll("string", patameterValue);
		} catch (FileNotFoundException e) {
			throw new SdkSystemException("无法找到请求模板文件");
		} catch (IOException e) {
			throw new SdkSystemException("无法读取请求模板文件");
		} finally {
			if (bufferedReader != null) {
				try {
					bufferedReader.close();
				} catch (IOException e) {
				}
			}
		}
	}
	// 删除Soap外壳信息
	private static String RemoveSoapShell(String source) {
		String result = "";
		int indexElementBegin = source.indexOf("<RequestResult>");
		int indexElementEnd = source.indexOf("</RequestResult>");
		if (indexElementBegin > 0 && indexElementEnd > 0) {
			result = source.substring(indexElementBegin
					+ "<RequestResult>".length(), indexElementEnd);
		}
		return result;
	}

	// 删除Soap外壳信息
	private static String RemoveSoapShell2(String source) {
		String result = "";
		int indexElementBegin = source.indexOf("<HandleResult>");
		int indexElementEnd = source.indexOf("</HandleResult>");
		if (indexElementBegin > 0 && indexElementEnd > 0) {
			result = source.substring(indexElementBegin
					+ "<HandleResult>".length(), indexElementEnd);
		}
		return result;
	}

	// 删除Soap外壳信息
	private static String RemoveSoapShellFromShareIntl(String source) {
		String result = "";
		int indexElementBegin = source.indexOf("<ProcessRequestResult>");
		int indexElementEnd = source.indexOf("</ProcessRequestResult>");
		if (indexElementBegin > 0 && indexElementEnd > 0) {
			result = source.substring(indexElementBegin
					+ "<ProcessRequestResult>".length(), indexElementEnd);
		}
		return result;
	}

	public static String SendTradeQuickApiRequest(String requestContent, String urlString, Proxy proxy) {
		InputStream errorStream = null;
		HttpURLConnection httpCon = null;
		try {
			URL url = new URL(urlString);

			String content = requestContent;

			if (proxy == null)
				httpCon = (HttpURLConnection) url.openConnection();
			else
				httpCon = (HttpURLConnection) url.openConnection(proxy);

			httpCon.setConnectTimeout(3000);
			httpCon.setReadTimeout(30000);

			httpCon.setRequestMethod("POST");
			httpCon.setDoOutput(true);
			httpCon.setDoInput(true);

			for (int i = 0; i < StaticHttpRequestProperty3.size(); i++) {
				httpCon.setRequestProperty(StaticHttpRequestProperty3.get(i).getName(),
						StaticHttpRequestProperty3.get(i).getValue());
			}

			httpCon.setRequestProperty("Content-Length", String.valueOf(content.length()));

			//用gzip方式压缩请求体并赋给request
			ByteArrayInputStream bis = new ByteArrayInputStream(content.getBytes("UTF-8"));
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			GZIPOutputStream gos = new GZIPOutputStream(bos);
			for (int c = bis.read(); c != -1; c = bis.read()) {
				gos.write(c);
			}
			gos.close();

			Date baseTime = DateUtil.getCurDateTime();

			OutputStream outputStream = httpCon.getOutputStream();
			outputStream.write(bos.toByteArray());
			outputStream.close();

			InputStream inputStream = httpCon.getInputStream();

			BufferedReader br = null;

			if (httpCon.getRequestProperty("Accept-Encoding") != null) {
				try {
					GZIPInputStream gzipStream = new GZIPInputStream(inputStream);
					br = new BufferedReader(new InputStreamReader(gzipStream, "UTF-8"));
				} catch (IOException e) {
					br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
				}
			} else {
				br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
			}
			StringBuffer result = new StringBuffer();
			String line = null;
			while ((line = br.readLine()) != null) {
				result.append(line);
			}

			long span = DateUtil.getPastTime(baseTime);
			logger.debug("请求耗时：　" + span + " ms.");

			return result.toString();

		} catch (MalformedURLException ex) {
			logger.error(ex.getMessage());
		} catch (SocketTimeoutException ex) {
			logger.error(ex.getMessage());
		} catch (IOException ex) {
			logger.error(ex.getMessage());
			errorStream = httpCon.getErrorStream();
			if (errorStream != null) {
				String errorMessage = null;
				String line = null;
				BufferedReader br = new BufferedReader(new InputStreamReader(
						errorStream));
				try {
					while ((line = br.readLine()) != null) {
						errorMessage += line;
					}
					logger.info(errorMessage);
					return errorMessage;
				} catch (IOException ex1) {
					logger.error(ex1.getMessage());
				}
			}
			logger.error(ex.getMessage());
			try {
				errorStream.close();
			} catch (IOException e1) {
				logger.error(e1.getMessage());
			}
		} catch (Exception ex) {
			logger.error(ex.getMessage());
		} finally {
			if (httpCon != null) {
				httpCon.disconnect();
			}
		}

		return "";
	}


	// 将xml文档转换为可传输的字符串
	private static String XMLToString(String source) {
		String result = source.replaceAll("<", "&lt;");
		result = result.replaceAll(">", "&gt;");
		return result;
	}

	// 将返回的字符串转换为可反序列化XML文本
	private static String StringToXML(String source) {
		String result = source.replaceAll("&lt;", "<");
		result = result.replaceAll("&gt;", ">");
		return result;
	}

	// 加载静态信息
	private static ArrayList<HttpRequestProperty> LoadStaticHttpRequestProperties() {
		ArrayList<HttpRequestProperty> staticHttpRequestProperty = new ArrayList<HttpRequestProperty>();
		staticHttpRequestProperty.add(new HttpRequestProperty("Content-Type", "text/xml; charset=UTF-8"));
		staticHttpRequestProperty.add(new HttpRequestProperty("SOAPAction", "http://ctrip.com/Request"));
		staticHttpRequestProperty.add(new HttpRequestProperty("Accept-Encoding", "gzip, deflate"));

		return staticHttpRequestProperty;
	}

	// 加载静态信息
	private static ArrayList<HttpRequestProperty> LoadStaticHttpRequestProperties2() {
		ArrayList<HttpRequestProperty> staticHttpRequestProperty = new ArrayList<HttpRequestProperty>();
		staticHttpRequestProperty.add(new HttpRequestProperty("Content-Type", "text/xml; charset=UTF-8"));
		staticHttpRequestProperty.add(new HttpRequestProperty("SOAPAction", "http://tempuri.org/Handle"));
		staticHttpRequestProperty.add(new HttpRequestProperty("Accept-Encoding", "gzip, deflate"));

		return staticHttpRequestProperty;
	}

	// 加载静态信息
	private static ArrayList<HttpRequestProperty> LoadStaticHttpRequestProperties3() {
		ArrayList<HttpRequestProperty> staticHttpRequestProperty = new ArrayList<HttpRequestProperty>();
		staticHttpRequestProperty.add(new HttpRequestProperty("Content-Type", "application/xml"));
		staticHttpRequestProperty.add(new HttpRequestProperty("Accept-Encoding", "gzip, deflate"));
		staticHttpRequestProperty.add(new HttpRequestProperty("Content-Encoding", "gzip"));

		return staticHttpRequestProperty;
	}
	private static ArrayList<HttpRequestProperty> LoadStaticHttpRequestProperties4() {
		ArrayList<HttpRequestProperty> staticHttpRequestProperty = new ArrayList<>();
		staticHttpRequestProperty.add(new HttpRequestProperty("Content-Type", "text/xml; charset=UTF-8"));
		staticHttpRequestProperty.add(new HttpRequestProperty("SOAPAction", "http://tempuri.org/ProcessRequest"));
//		staticHttpRequestProperty.add(new HttpRequestProperty("Accept-Encoding", "gzip, deflate"));

		return staticHttpRequestProperty;
	}

	private static String createRequestXml(String allianceId, String sid, String secretKey) {
		StringBuilder sb = new StringBuilder();
		try {
			sb.append("<Request><Header AllianceID=\"");
			sb.append(allianceId);
			sb.append("\" SID=\"");
			sb.append(sid);
			sb.append("\" TimeStamp=\"");
			long timestamp = SignatureUtils.GetTimeStamp();
			sb.append(timestamp);
			sb.append("\" Signature=\"");
	
			String signature = SignatureUtils.CalculationSignature(timestamp
					+ "", allianceId, secretKey, sid, ConfigData.RequestType);
			sb.append(signature);
			sb.append("\" RequestType=\"");
			sb.append(ConfigData.RequestType);
			sb.append("\" AsyncRequest=\"false\" Timeout=\"0\" MessagePriority=\"3\"/><HotelRequest><RequestBody xmlns:ns=\"http://www.opentravel.org/OTA/2003/05\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><ns:OTA_PingRQ><ns:EchoData>联通测试</ns:EchoData></ns:OTA_PingRQ></RequestBody></HotelRequest></Request>");
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
		return sb.toString();
	}

}
